package block;

import java.awt.*;
import java.io.*;

import util.Util;

public class CombinationBlock extends LogicBlock {

    public int outputNum, inputNum;
    public int[] allOutputs;
    public int[] inputPorts, outputPorts;
    public String name;
    public int[] newOutputs;


    public CombinationBlock(int startX, int startY, int row, int column, int inputNum, int outputNum, int[] allOutputs, boolean[][] taken, String name){
        super(startX, startY, column, row, taken);
        this.allOutputs = allOutputs;
        this.outputNum = outputNum;
        this.inputNum = inputNum;
        this.name = name;

        inputPorts = new int[inputNum]; // default port setting
        for(int i = 0; i < inputNum; i ++)
            inputPorts[i] = i;
        outputPorts = new int[outputNum];
        for(int i = 0; i < outputNum; i ++)
            outputPorts[i] = i;
    }

    public static void writeToFile(String fileName, int inputNum, int outputNum, int[] allOutputs) throws IOException{
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));
        out.write(inputNum);
        out.write(outputNum);
        for(int i = 0; i < allOutputs.length; i ++)
            out.write(allOutputs[i]);
        out.flush();
        out.close();
    }

    @Override
    public void draw(Graphics g, int unit, int zeroX, int zeroY){
        String display = name;
        if(outputs != -1){
            display = display + ":";
            for(int i = 0; i < outputNum; i ++)
                display = display + newOutputs[i];
        }
        super.draw(g, unit, zeroX, zeroY);
        g.drawString(display, zeroX + unit * startX, zeroY + unit * startY + 12);
        for(int i = 0; i < inputNum; i ++)
            g.drawString(Integer.toString(inputPorts[i]), zeroX + unit * startX, zeroY + unit * startY + unit / 2 + i * unit);
        for(int i = 0; i < outputNum; i ++)
            g.drawString(Integer.toString(outputPorts[i]), zeroX + unit * (startX + column) - 14, zeroY + unit * startY + unit / 2 + i * unit);
    }

    public void fulfill(int[] inputs){

    }

    @Override
    public void run(int[][] cond){
        int i;
        for(i = startY; i < startY + inputNum; i ++)
            if(cond[startX][inputPorts[i] + startY] == -1) {
                outputs = -1;
                return;
            }

        int[] newInputs = new int[inputNum];
        for(i = 0; i < inputNum; i ++)
            newInputs[i] = cond[startX][inputPorts[i] + startY];
        outputs = allOutputs[Util.BiToDec(newInputs)];
        int[] oldOutputs = Util.DecToBi(outputNum, outputs);
        newOutputs = new int[outputNum];
        for(i = 0; i < outputNum; i ++)
            newOutputs[outputPorts[i]] = oldOutputs[i];
        for(i = 0; i < outputNum; i ++){
            cond[startX + column][i + startY] = newOutputs[i];
        }
        for(int j = i;j < inputNum; j ++)
            cond[startX + column][j + startY] = newOutputs[i - 1];
    }

    public String getInputPorts(){
        String retDat = "";
        for(int i = 0; i < inputNum; i ++)
            retDat = retDat + i;
        return retDat;
    }

    public String getOutputPorts(){
        String retDat = "";
        for(int i = 0; i < outputNum; i ++)
            retDat = retDat + i;
        return retDat;
    }

    public boolean changePort(int in, int out){
        int[] inArray = Util.divide(in, inputNum);
        int[] outArray = Util.divide(out, outputNum);
        for(int i = 0; i < inputNum; i ++) {
            if (inArray[i] > inputNum - 1)
                return false;
        }
        for(int i = 0; i < outputNum; i ++){
            if(outArray[i] > outputNum - 1)
                return false;
        }

        for(int i = 0; i < inputNum; i ++)
            inputPorts[i] = inArray[inputNum - 1 - i];
        for(int i = 0; i < outputNum; i ++)
            outputPorts[i] = outArray[outputNum - 1 - i];
        return true;
    }
}
